package de.tum.in.eist.im.client.Chat;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.TabLayoutPanel;
import com.google.gwt.user.client.ui.VerticalPanel;

import de.tum.in.eist.im.client.Chat.Channel.Channel;
import de.tum.in.eist.im.client.Chat.Channel.ChannelFactory;
import de.tum.in.eist.im.client.Chat.Channel.SocketListener;
import de.tum.in.eist.im.client.Chat.ChatChannel.ChatMessageHandler;
import de.tum.in.eist.im.client.Chat.CreateChatChannelTab.CreateChatChannelTab;
import de.tum.in.eist.im.client.Login.LoginPanel;
import de.tum.in.eist.im.shared.ChatChannel.ChatChannel;
import de.tum.in.eist.im.shared.Message.Message;
import de.tum.in.eist.im.shared.PatternMatch.PatternMatch;
import de.tum.in.eist.im.shared.User.User;

public class ChatPanel {
	
	// private variables
	private User user;
	private ChatPanelHandler chatPanelHandler;
	private DockLayoutPanel dockLayoutPanel = new DockLayoutPanel(Unit.EM);
	private TabLayoutPanel tabLayoutPanel = new TabLayoutPanel(1.5, Unit.EM);
	private VerticalPanel onlineUserPanel = new VerticalPanel();
	private VerticalPanel openChatChannels = new VerticalPanel();
	private List<Long> openTabs = new ArrayList<Long>();
	private List<ChatMessageHandler> chatMessageHandlerList = new ArrayList<ChatMessageHandler>();
	
	private String serverApiToken = null;

	/**
	 * The ChatPanel class creates the main layout for the chat
	 * @param user the user who is login
	 */
	public ChatPanel(User user) {
		
		// add user to the instance variable
		this.user = user;
		
		// create a chatPanel Handler
		chatPanelHandler = new ChatPanelHandler(this, this.user);
		
		// receive a serverApiToken
		chatPanelHandler.receiveApiTokenToCreateChannel();
		
		// clear root layout panel
		RootLayoutPanel rootPanel = RootLayoutPanel.get();
		rootPanel.clear();

		// create vertical panel for the east frame
		VerticalPanel eastVerticalPanel = new VerticalPanel();
		eastVerticalPanel.setSize("140px", "100%");
		eastVerticalPanel.add(onlineUserPanel);
		eastVerticalPanel.add(openChatChannels);
		
		// add button for creating a new group
		Button addTabButton = new Button();
		addTabButton.setText("Create Chat Group");
		addTabButton.setSize("140px", "40px");
		eastVerticalPanel.add(addTabButton);
		
		// add button for logout
		Button logoutButton = new Button();
		logoutButton.setText("Logout");
		logoutButton.setSize("140px", "40px");
		eastVerticalPanel.add(logoutButton);
		
		// add click handler functionality to addTabButton
		addTabButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				ChatPanel.this.creatChatTutorialTab();
			}		
		});
		
		// add click handler functionality to logoutButton
		logoutButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				ChatPanel.this.removeUser();
				new LoginPanel();
			}
		});
		
		// add dock layout panel
		dockLayoutPanel.addEast(eastVerticalPanel, 10);
		dockLayoutPanel.add(tabLayoutPanel);
		rootPanel.add(dockLayoutPanel);
	}
	
	/**
	 * sets the server api token for this client
	 * @param apiToken the api token
	 */
	public void setApiToken(String apiToken) {
		this.serverApiToken = apiToken;
		this.openPushConnection();
	}
	
	/**
	 * the push connection to receive new messages
	 * @param channelAPIToken the token of the channel
	 */
	public void openPushConnection () {
		Channel channel = ChannelFactory.createChannel(serverApiToken);
		
		ChatPanel.this.chatPanelHandler.getOnlineUsersFromServer();
		ChatPanel.this.chatPanelHandler.getOpenGroups();

		this.chatPanelHandler.addUserAsOnline();
		channel.open(new SocketListener() {
		        @Override
		        public void onMessage(String result) {
		        	
		        	// build message object out of JSON object
		        	String[] messageString = PatternMatch.parseJsonMessage(result);
		        	
		        	// decide what is the result
		        	// 1 : list a message
		        	// 2 : list of all online users
		        	// 3 : list of all chat channels
		        	// 4 : force to open a chat tab
		        	if (Integer.parseInt(messageString[0]) == 1) {
		        		ChatPanel.this.handleNewMessage(result);			     
			        // get all online users
		        	} else if (Integer.parseInt(messageString[0]) == 2) {
		        		ChatPanel.this.handleNewGetAllOnlineUser(result);
		        	// get all open chat channel
		        	} else if (Integer.parseInt(messageString[0]) == 3) {
		        		ChatPanel.this.handleNewGetAllOpenChats(result);
		        	// get all online users of a specific channel
		        	} else if (Integer.parseInt(messageString[0]) == 4) {
		        		ChatPanel.this.handleForceOpenTab(result);
		        	}
		        }
		        
		        @Override
		        public void onOpen() {
		        	// what should happen if the channel opens
		        }
		});
	}
	
	/**
	 * handle a new message string
	 * @param result the json string
	 */
	public void handleNewMessage(String result) {
		
    	String[] messageString = PatternMatch.parseJsonMessage(result);
		
    	// create a new message of the JSON string
    	String messageText = messageString[1];
    	User messageUser = new User(messageString[2]);
    	
    	// default Date - todo convert string to date
    	Date messageDate = null; // convert Date to String
    	Long messageChatId = Long.parseLong(messageString[4]);
    	
    	// construct new object
    	Message newMessage = new Message(messageText, messageUser, messageDate, messageChatId);
    	for (ChatMessageHandler cMH : chatMessageHandlerList) {
    		if (cMH.getChatChannelId().equals(newMessage.getMessageChatId()))
    			cMH.addChatMessage(newMessage);
    	}
	}
	
	/**
	 * handle a new online user
	 * @param result the json string
	 */
	public void  handleNewGetAllOnlineUser(String result) {
    	String[] messageString = PatternMatch.parseJsonMessage(result);
		List<User> userList = new ArrayList<User>();
		for (int i = 1; i < messageString.length; i++) {
			userList.add(new User(messageString[i]));
		}
		
		ChatPanel.this.clearListOfOnlineUser();
		for (User u : userList) {
			ChatPanel.this.addUserToListOfOnlineUser(u);
		}
	}
	
	/**
	 * handle a new open chat message
	 * @param result the json string
	 */
	public void handleNewGetAllOpenChats(String result) {
    	String[] messageString = PatternMatch.parseJsonMessage(result);
		List<ChatChannel> chatChannelList = new ArrayList<ChatChannel>();
		for (int i = 1; i < messageString.length; i = i + 2) {
			chatChannelList.add(new ChatChannel(Long.parseLong(messageString[i+1]), messageString[i]));
		}
		
		ChatPanel.this.clearListOfChatChannels();
		for (ChatChannel cC : chatChannelList) {
			ChatPanel.this.addChatChannelToListOfOpenChannels(cC);
		}	
	}
	
	/**
	 * the user is forced to open a tab
	 * @param result the json string
	 */
	public void handleForceOpenTab(String result) {
		String[] messageString = PatternMatch.parseJsonMessage(result);
		this.requestPrivateChatTab(new User(messageString[2]), new User(messageString[1]), new Button());
	}
	
	/** 
	 * checks if a group already existed and then open the group and the tab
	 * @param title title of the new group/tab
	 */
	public void requestChatTab (String title) {
		// get id of conversation
		chatPanelHandler.getChannelId(title);
	}
	
	/**
	 * request a private chat tab with an other user
	 * @param selfUser this user
	 * @param otherUser the other user clicked
	 */
	public void requestPrivateChatTab (User selfUser, User otherUser, Button clickedUserButton) {
		if (selfUser.getUsername().equals(otherUser.getUsername()))
			return;
		chatPanelHandler.getPrivateChatChannelId(selfUser, otherUser, clickedUserButton);
	}
	
	/**
	 * remove the user
	 */
	public void removeUser() {
		// logout user
		chatPanelHandler.removeUserAsOnline();
		new LoginPanel();
	}
	
	/**
	 * close the current tab
	 
	public void closeTab() {
		tabLayoutPanel.remove(tabLayoutPanel.getSelectedIndex());
		if (tabLayoutPanel.getWidgetCount() > 0) {
			tabLayoutPanel.selectTab(0);
		} else {
			new LoginPanel();
		}
	}
	*/
	
	/**
	 * creates a new chat tab/group
	 * @param title title of the tab/group
	 * @param chatChannelId id of the group
	 */
	public void addChatTab (String title, Long chatChannelId) {
		
		// check if you got a valid channel id
		if (-1 == chatChannelId) {
			return;
		}
		
		boolean foundTab = false;
		for (Long o : openTabs) {
			if (o.equals(chatChannelId))
				foundTab = true;
		}
		if (foundTab)
			return;
		
		// create chat message handler and send message panel
		ChatMessageHandler chatMessageHandler = new ChatMessageHandler(chatChannelId, this.user);
		
		// TODO: if user close tab delete this list entry
		boolean foundChatChannel = false;
		for (ChatMessageHandler cMH : chatMessageHandlerList) {
			if (cMH.getChatChannelId().equals(chatChannelId))
				foundChatChannel = true;
		}
		
		if (!foundChatChannel)
			chatMessageHandlerList.add(chatMessageHandler);
		
		VerticalPanel verticalPanel = new VerticalPanel();
		verticalPanel.add(chatMessageHandler.getWidget());
		verticalPanel.add(chatMessageHandler.getSendMessageWidget());
		
		// create tab
		tabLayoutPanel.add(verticalPanel, title);
		openTabs.add(chatChannelId);
	}
	
	/**
	 * creates a new tab where the user can add new groups
	 */
	public void creatChatTutorialTab() {
		
		boolean foundTab = false;
		for (Long o : openTabs) {
			if (o.equals(new Long(-1)))
				foundTab = true;
		}
		if (foundTab)
			return;
		else 
			openTabs.add(new Long(-1));
		
		CreateChatChannelTab chatCreateGroupPanel = new CreateChatChannelTab(this);
		tabLayoutPanel.add(chatCreateGroupPanel.getWidget(), "Add Group");
	}
	
	/**
	 * add a user to the list of online User ass button so you can start a private conversation
	 * @param user user you want to add to the list of online user
	 */
	public void addUserToListOfOnlineUser(final User user) {	
		final Button newUserButton = new Button();
		newUserButton.setText(user.getUsername());
		
		newUserButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				ChatPanel.this.requestPrivateChatTab(ChatPanel.this.user, user, newUserButton);
				newUserButton.setEnabled(false);
			}
		});
		onlineUserPanel.add(newUserButton);
	}
	
	/**
	 * clear the list of online user
	 */
	public void clearListOfOnlineUser() {
		onlineUserPanel.clear();
	}
	
	/**
	 * add a chat channel to the list of open chat channels
	 * @param chat channel to display
	 */
	public void addChatChannelToListOfOpenChannels(final ChatChannel chatChannel) {
		Button newChatChannelButton = new Button();
		newChatChannelButton.setText(chatChannel.getTitle());	
		newChatChannelButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				ChatPanel.this.addChatTab(chatChannel.getTitle(), chatChannel.getChatId());
				chatChannel.addUserToChatChannel(ChatPanel.this.user);
			}
		});
		openChatChannels.add(newChatChannelButton);
	}
	
	/**
	 * clear the list of open chat channels
	 */
	public void clearListOfChatChannels() {
		openChatChannels.clear();
	}
}
